package com.changzhi.common.exception;


import com.changzhi.common.enums.StatusCodeEnum;
import com.changzhi.common.util.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.List;

/**
 * 全局配置
 *
 * @author zhongsh
 * @version 2017/1/11
 */
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {


    /**
     * DuplicateKeyException异常处理，主键重复
     *
     * @param exception
     * @return 返回JSON
     */
    @ExceptionHandler(DuplicateKeyException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public Result duplicateKeyHandler(DuplicateKeyException exception) {
        return Result.error(StatusCodeEnum.ERROR_DUPLICATE_KEY);
    }

    /**
     * Assert抛出的异常处理
     *
     * @param exception
     * @return 返回JSON
     */
    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public Result illegalArgumentExceptionHandler(IllegalArgumentException exception) {
        log.error(exception.getMessage(), exception);
        return Result.error(exception.getMessage());
    }

    /**
     * 自定义业务逻辑异常处理
     *
     * @param exception
     * @return 返回JSON
     */
    @ExceptionHandler(ServiceException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public Result serviceExceptionHandler(ServiceException exception) {
        return exception.getResult();
    }


    /**
     * 其它异常处理
     *
     * @param exception
     * @return 返回JSON
     */
    @ExceptionHandler
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public Result exceptionHandler(Exception exception) {
        log.error(exception.getMessage(), exception);
        return Result.error("操作失败，发生系统错误！");
    }

    /**
     * @param exception
     * @return 返回JSON
     * @Valid，@Validated校验，参数绑定出错
     */
    @ExceptionHandler({ MethodArgumentNotValidException.class, BindException.class})
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public Result validExceptionHandler(Exception exception) {
        BindingResult bindingResult = null;
        if (exception instanceof MethodArgumentNotValidException) {
            bindingResult = ((MethodArgumentNotValidException) exception).getBindingResult();
        }
        if (exception instanceof BindException) {
            bindingResult = ((BindException) exception).getBindingResult();
        }
        String errorMessage = getErrorMessage(bindingResult);
        log.warn("参数绑定出错：{}", errorMessage);
        return Result.error("参数错误：" + errorMessage);
    }

    /**
     * 从BindingResult获取错误信息
     *
     * @param bindingResults
     * @return 错误信息，如果返回null表示没有错误
     */
    private String getErrorMessage(BindingResult... bindingResults) {
        if (bindingResults == null || bindingResults.length == 0) {
            return null;
        }
        for (BindingResult bindingResult : bindingResults) {
            List<ObjectError> allErrors = bindingResult.getAllErrors();
            if (allErrors == null || allErrors.size() == 0) {
                continue;
            }
            ObjectError objectError = allErrors.get(0);
            String defaultMessage = objectError.getDefaultMessage();
            if (StringUtils.isNotBlank(defaultMessage)) {
                return defaultMessage;
            }
            if (objectError instanceof FieldError) {
                FieldError fieldError = (FieldError) objectError;
                return fieldError.getField() + "[" + fieldError.getRejectedValue().toString() + "]";
            }
            return "";
        }
        return null;
    }
}